using shaco.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using YooAsset;

namespace shaco
{
    internal class YooAssetResourceHandle : IResourceHandle
    {
        public object assetObject => _handle.AssetObject;
        public float progress => _handle.Progress;
        public bool isDone => _handle.IsDone;
        public AssetHandle handle => _handle;
        public object Current => _handle;

        AssetHandle _handle;

        internal void SetHandle(AssetHandle handle)
        {
            _handle = handle;
        }

        public void OnCompleted(Action<IResourceHandleBase> callback)
        {
            _handle.Completed += s => callback(this);
        }

        public bool MoveNext()
        {
            return !_handle.IsDone;
        }

        public void Reset()
        {
        }

        public void Release()
        {
            _handle?.Release();
        }
    }

    internal class YooAssetAllResourceHandle : IAllResourceHandle
    {
        public IEnumerable<object> assetObjects => _handle.AllAssetObjects.Select(v => (object)v);
        public float progress => _handle.Progress;
        public bool isDone => _handle.IsDone;
        public AllAssetsHandle handle => _handle;
        public object Current => _handle;

        AllAssetsHandle _handle;

        internal void SetHandle(AllAssetsHandle handle)
        {
            _handle = handle;
        }

        public void OnCompleted(Action<IResourceHandleBase> callback)
        {
            _handle.Completed += s => callback(this);
        }

        public bool MoveNext()
        {
            return !_handle.IsDone;
        }

        public void Reset()
        {
        }

        public void Release()
        {
            _handle?.Release();
        }
    }

    public class YooAssetResources : IResources
    {
        virtual public string currentPackageName => _currentPackage?.PackageName;
        Dictionary<string, ResourcePackage> _packages = new ();
        ResourcePackage _currentPackage = null;

        public bool Exists(string path)
        {
            CheckDefaultPackageValid();
            return _currentPackage.CheckLocationValid(path);
        }

        public bool Exists(IResourceHandleBase handle)
        {
            CheckDefaultPackageValid();
            if (handle is YooAssetResourceHandle)
                return Exists((handle as YooAssetResourceHandle).handle.GetAssetInfo().AssetPath);
            else if (handle is YooAssetAllResourceHandle)
                return Exists((handle as YooAssetAllResourceHandle).handle.GetAssetInfo().AssetPath);
            else
                throw new NotImplementedException("YooAssetResources Exists error: unsupport type=" + handle?.GetType());
        }

        public IResourceHandle Load(string path, Type type)
        {
            CheckDefaultPackageValid();
            var handle = _currentPackage.LoadAssetSync(path, type);
            var retValue = shaco.GameHelper.objectpool.Instantiate(() => new YooAssetResourceHandle());
            retValue.SetHandle(handle);
            return retValue;
        }

        public IResourceHandle Load<T>(string path) where T : UnityEngine.Object
        {
            CheckDefaultPackageValid();
            var handle = _currentPackage.LoadAssetSync<T>(path);
            var retValue = shaco.GameHelper.objectpool.Instantiate(() => new YooAssetResourceHandle());
            retValue.SetHandle(handle);
            return retValue;
        }

        public IAllResourceHandle LoadAll<T>(string path) where T : UnityEngine.Object
        {
            CheckDefaultPackageValid();
            var handle = _currentPackage.LoadAllAssetsSync<T>(path);
            var retValue = shaco.GameHelper.objectpool.Instantiate(() => new YooAssetAllResourceHandle());
            retValue.SetHandle(handle);
            return retValue;
        }

        public IAllResourceHandle LoadAllAsync<T>(string path) where T : UnityEngine.Object
        {
            CheckDefaultPackageValid();
            var handle = _currentPackage.LoadAllAssetsAsync<T>(path);
            var retValue = shaco.GameHelper.objectpool.Instantiate(() => new YooAssetAllResourceHandle());
            retValue.SetHandle(handle);
            return retValue;
        }

        public IResourceHandle LoadAsync<T>(string path) where T : UnityEngine.Object
        {
            CheckDefaultPackageValid();
            var handle = _currentPackage.LoadAssetAsync<T>(path);
            var retValue = shaco.GameHelper.objectpool.Instantiate(() => new YooAssetResourceHandle());
            retValue.SetHandle(handle);
            return retValue;
        }

        public void Release(IResourceHandleBase handle)
        {
            handle.RecyclingWithPool();
            
            CheckDefaultPackageValid();
            if (handle is YooAssetResourceHandle)
            {
                var handleTmp = handle as YooAssetResourceHandle;
                handleTmp.handle.Release();
            }
            else if (handle is YooAssetAllResourceHandle)
            {
                var handleTmp = handle as YooAssetAllResourceHandle;
                handleTmp.handle.Release();
            }
            else
                throw new NotImplementedException("YooAssetResources Unload error: unsupport type=" + handle?.GetType());
        }

        public void TryUnloadUnusedAsset(IResourceHandleBase handle)
        {
            CheckDefaultPackageValid();
            if (handle is YooAssetResourceHandle)
            {
                var handleTmp = handle as YooAssetResourceHandle;
                _currentPackage.TryUnloadUnusedAsset(handleTmp.handle.GetAssetInfo());
            }
            else if (handle is YooAssetAllResourceHandle)
            {
                var handleTmp = handle as YooAssetAllResourceHandle;
                _currentPackage.TryUnloadUnusedAsset(handleTmp.handle.GetAssetInfo());
            }
            else
                throw new NotImplementedException("YooAssetResources TryUnloadUnusedAsset error: unsupport type=" + handle?.GetType());

        }

        public System.Collections.IEnumerator UnloadUnusedAssetsAsync()
        {
            CheckDefaultPackageValid();
            return _currentPackage.UnloadUnusedAssetsAsync();
        }

        public void SetCurrentPackageName(string packageName)
        {
            if (!_packages.TryGetValue(packageName, out _currentPackage))
            {
                _currentPackage = YooAssets.GetPackage(packageName);
                _packages.Add(packageName, _currentPackage);
            }
            YooAssets.SetDefaultPackage(_currentPackage);
        }

        [System.Diagnostics.Conditional("DEBUG")]
        void CheckDefaultPackageValid()
        {
            if (null == _currentPackage)
                throw new Exception("还没有设置当前资源包");
        }
    }
}